using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Security;

using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Security.Permissions;


using WMOSSExperts.Fields;
using WMOSSExperts.Diagnostics;

namespace WMOSSExperts.WebControls
{
    [CLSCompliant(false)]
    [SharePointPermissionAttribute(SecurityAction.InheritanceDemand, ObjectModel = true)]
    [AspNetHostingPermissionAttribute(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [SharePointPermissionAttribute(SecurityAction.LinkDemand, ObjectModel = true)]
    [AspNetHostingPermissionAttribute(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class RelatedLookupLinkControl : BaseFieldControl, System.Web.UI.ICallbackEventHandler
    {
        #region "Constants"
        private const String _kJsRetrieveChildItems = "RetrieveChildItems";
        private const String _kJsGetChildItems = "GetChildListItems";
        private const String _kJsDisplayErrorRelatedLookup = "DisplayErrorRelatedLookup";
        private const String _kHtmlMenusId = "relatedLookupMenu";
        private const String _kHtmlClassTabSelected = "ms-templatepickerselected";
        private const String _kHtmlClassTabUnSelected = "ms-templatepickerunselected";

        #endregion

        private HtmlGenericControl container;
        private HtmlGenericControl tabMenu;
        private HtmlGenericControl tabDetail;

        protected String returnValueAjax;
        protected String tabDetailUniqueId = Guid.NewGuid().ToString();


        /// <summary>
        /// Create and register Javascript used in the AJAX process
        /// </summary>
        private void RegisterAjaxScript()
        {
            //Get the callback event reference for this control
            String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", _kJsRetrieveChildItems, "context", _kJsDisplayErrorRelatedLookup, true);

            //Create the script function to call the server function which retrieves  child sourceList items
            StringBuilder callbackScript = new StringBuilder();
            callbackScript.AppendFormat("function {0}(caller, arg, context)",_kJsGetChildItems);
            callbackScript.AppendLine("{");
            callbackScript.AppendFormat("var menus = document.getElementsByName('{0}');",_kHtmlMenusId);
            callbackScript.AppendLine();
            callbackScript.AppendLine("if (menus==null) {alert('An error occurs, please contact your sharepoint administrator'); return;}");
            callbackScript.Append("for(i=0;i<menus.length;i++){");
            callbackScript.AppendFormat("menus[i].className='{0}';",_kHtmlClassTabUnSelected);
            callbackScript.Append("}");
            callbackScript.AppendLine();
            callbackScript.AppendFormat("caller.className='{0}';",_kHtmlClassTabSelected);
            callbackScript.AppendLine();
            callbackScript.AppendFormat("var tabDetail=document.getElementById('{0}');", tabDetailUniqueId);
            callbackScript.AppendLine("if (tabDetail==null) {alert('An error occurs, please contact your sharepoint administrator'); return;}");
            callbackScript.AppendLine("tabDetail.innerHTML = \"<table cellpadding='20' style='width: 100%;Text-align: center;background-color: White;'><tr><td><img src='/_layouts/images/GEARS_AN.GIF'/><div><b>Please wait...</b></div></td></tr></table>\";");
            callbackScript.AppendLine(cbReference + ";");
            callbackScript.AppendLine("}");

            //Create the script function to display the sourceList child items
            StringBuilder retrieveAjaxValueScript = new StringBuilder();
            retrieveAjaxValueScript.AppendFormat("function {0}(rValue)",_kJsRetrieveChildItems);
            retrieveAjaxValueScript.AppendLine("{");
            //Search the container
            retrieveAjaxValueScript.AppendFormat("var tabDetail=document.getElementById('{0}');", tabDetailUniqueId);
            retrieveAjaxValueScript.AppendLine("if (tabDetail==null) {alert('An error occurs, please contact your sharepoint administrator'); return;}");
            retrieveAjaxValueScript.AppendLine("try{");

            //Load the response as a xml object
            //retrieveAjaxValueScript.AppendLine("var doc = null;");
            //retrieveAjaxValueScript.AppendLine("if (document.implementation && document.implementation.createDocument)");
            //retrieveAjaxValueScript.AppendLine("doc = document.implementation.createDocument(\"\", \"\", null);");
            //retrieveAjaxValueScript.AppendLine("else");
            //retrieveAjaxValueScript.AppendLine("doc = new ActiveXObject(\"MSXML2.DOMDocument\");");
            //retrieveAjaxValueScript.AppendLine("doc.loadXML(rValue);");
            //check the xml parsing
            //retrieveAjaxValueScript.AppendLine("if (doc.parseError.errorCode != 0){tabDetail.innerHTML = doc.parseError.reason;return;}");

            //retrieveAjaxValueScript.AppendLine("alert(rValue);");

            //load the value
            retrieveAjaxValueScript.AppendLine("tabDetail.innerHTML = rValue;");

            //browse tag scripts to evaluate them
            //retrieveAjaxValueScript.AppendLine("doc.setProperty(\"SelectionLanguage\", \"XPath\");");
            //retrieveAjaxValueScript.AppendLine("objNodeList = doc.documentElement.selectNodes(\"//script\");");
            //retrieveAjaxValueScript.AppendLine("for (i = 0; i < objNodeList.length; i++){");
            //retrieveAjaxValueScript.AppendLine("eval(objNodeList[i].text);}");

            retrieveAjaxValueScript.AppendLine("window.execScript(tabDetail.childNodes(0).childNodes(0).innerHTML,'javascript');");

            //end bloc try
            retrieveAjaxValueScript.AppendLine("}");

            //Create an exception catcher
            retrieveAjaxValueScript.AppendLine("catch(e){}");//tabDetail.innerHTML = \"Error occured : \" + e.description;}");
            
            //retrieveAjaxValueScript.AppendLine();

            //end function
            retrieveAjaxValueScript.AppendLine("}");

            //Create the script function to display an unexpected error
            StringBuilder retrieveAjaxErrorScript = new StringBuilder();
            retrieveAjaxErrorScript.AppendFormat("function {0}()",_kJsDisplayErrorRelatedLookup);
            retrieveAjaxErrorScript.AppendLine("{");
            retrieveAjaxErrorScript.AppendFormat("var tabDetail=document.getElementById('{0}');", tabDetailUniqueId);
            retrieveAjaxErrorScript.AppendLine("if (tabDetail==null) {alert('An error occurs, please contact your sharepoint administrator'); return;}");

            retrieveAjaxErrorScript.AppendLine("tabDetail.innerHTML = 'An expected error has occured';");
            retrieveAjaxErrorScript.AppendLine("}");

            //Register scripts
            if (!Page.ClientScript.IsClientScriptBlockRegistered(_kJsRetrieveChildItems))
                Page.ClientScript.RegisterClientScriptBlock(this.GetType(), _kJsRetrieveChildItems, retrieveAjaxValueScript.ToString(), true);

            if (!Page.ClientScript.IsClientScriptBlockRegistered(_kJsDisplayErrorRelatedLookup))
                Page.ClientScript.RegisterClientScriptBlock(this.GetType(), _kJsDisplayErrorRelatedLookup, retrieveAjaxErrorScript.ToString(), true);


            if (!Page.ClientScript.IsClientScriptBlockRegistered(_kJsGetChildItems))
                Page.ClientScript.RegisterClientScriptBlock(this.GetType(), _kJsGetChildItems, callbackScript.ToString(), true);

        }


        /// <summary>
        /// Create the control
        /// </summary>
        protected override void CreateChildControls()
        {

            if (Page.IsCallback) return;

            base.CreateChildControls();

            container = new HtmlGenericControl("div");
            container.Attributes.Add("class", "WMOSS_Container");

            //Create the two containers; one for menu qnd other for detail
            tabMenu = new HtmlGenericControl("div");
            tabMenu.Attributes.Add("class", "WMOSS_TabMenus");

            tabDetail = new HtmlGenericControl("div");
            tabDetail.Attributes.Add("class", "WMOSS_TabDetail");
            tabDetail.Attributes.Add("id", tabDetailUniqueId);

            container.Controls.Add(tabMenu);
            container.Controls.Add(tabDetail);


            this.CreateMenuList();
            tabDetail.InnerHtml = this.GetListViewDetail(0);
            base.Controls.Add(container);

            this.RegisterAjaxScript();

            
        }

       
       
        /// <summary>
        /// Get the child sourceList items
        /// </summary>
        /// <param name="relatedListIndex"></param>
        /// <returns></returns>
        private String GetListViewDetail(Int32 relatedListIndex)
        {
            String returnValue = String.Empty;
            String errorMessage = "There is an unexpected value, child items can't be rendered";
            Boolean hasError = true;

            RelatedLookupLinksField field = (RelatedLookupLinksField)this.Field;
            List<RelatedLookupLinksValue> relatedLists = field.GetRelatedLists(false);

            //Verify if there are items
            if (relatedListIndex < 0 | relatedLists.Count == 0 | relatedListIndex >= relatedLists.Count)
                return "There is no related sourceList to display. Verify that you have selected related sourceList";

            AdvancedLookupField reverseLookup = null;
            try
            {
                RelatedLookupLinksValue relatedList = relatedLists[relatedListIndex];
                reverseLookup = (AdvancedLookupField)this.Fields[relatedList.ReverseLookupId];
                
                if (reverseLookup != null)
                {
                    using (SPWeb web = SPContext.Current.Site.OpenWeb(reverseLookup.LookupWebId))
                    {
                        SPList list = web.Lists[new Guid(reverseLookup.LookupList)];
                        SPView view = list.Views[relatedList.FilteredViewId];
                        //Find the group by clause to remove it
                        Int32 iPosGroupBy = view.Query.IndexOf("</GroupBy>");
                        if (iPosGroupBy >= 0)
                        {
                            view.Query = view.Query.Substring(iPosGroupBy + 10);
                        }
                        view.Query = view.Query.Replace("<GetVar Scope=\"Request\" Name=\"Value\" />", "<GetVar Scope=\"Request\" Name=\"ID\" />");

                        returnValue = view.RenderAsHtml(false, false, view.Url);
                        if (returnValue.StartsWith("<script>", StringComparison.InvariantCultureIgnoreCase))
                        {
                            returnValue = "<TABLE width=\"100%\" cellspacing=0 cellpadding=0 border=0>" + returnValue + "</TABLE>";
                        }
                        /*returnValue = returnValue.Replace("<SCRIPT>", "<script>ctx1 = function AjaxEval(){");
                        returnValue = returnValue.Replace("</SCRIPT>", "return ctx;}</script>");*/

                        hasError = false;
                    }
                }
            }
            catch(Exception ex)
            {
                String message = String.Format("GetListViewDetail fails for List {0} and Field id {1}; cause to the following error {2}", this.Field.ParentList.Title, this.Field.Id, ex);
                TraceProvider.WriteTrace(TraceProvider.TraceSeverity.Exception, LogCategory.WMOSSExpertsCore, message);
                hasError = true;
            }

            if (hasError)
            {
                returnValue = errorMessage;
            }

            return returnValue;
        }

        /// <summary>
        /// Create the menu sourceList
        /// </summary>
        private void CreateMenuList()
        {
            //read reverseLookupField configuration
            RelatedLookupLinksField field = (RelatedLookupLinksField)this.Field;
            Int32 cpt = 0;
            foreach(RelatedLookupLinksValue list in field.GetRelatedLists(false))
            {
                HtmlGenericControl dvTab = new HtmlGenericControl("div");
                dvTab.Attributes.Add("onclick", String.Format("{0}(this,'{1}','');return false;", _kJsGetChildItems,cpt));
                dvTab.Attributes.Add("id", _kHtmlMenusId);
                dvTab.Attributes.Add("Style", "cursor: hand;");
                if (cpt == 0)
                    dvTab.Attributes.Add("class", _kHtmlClassTabSelected);
                else
                    dvTab.Attributes.Add("class", _kHtmlClassTabUnSelected);

                HtmlGenericControl dvTab2 = new HtmlGenericControl("div");
                dvTab2.InnerText = list.ChildList;
                dvTab.Controls.Add(dvTab2);

                tabMenu.Controls.Add(dvTab);
                cpt++;
            }
        }

        
        /// <summary>
        /// Render the control
        /// </summary>
        /// <param name="output"></param>
        protected override void Render(System.Web.UI.HtmlTextWriter output)
        {
            this.container.RenderControl(output);
        }

        #region ICallbackEventHandler Members

        /// <summary>
        /// Gets the AJAX result
        /// </summary>
        /// <returns></returns>
        public string GetCallbackResult()
        {
            return returnValueAjax;
        }

        /// <summary>
        /// Handle the ajax call
        /// </summary>
        /// <param name="eventArgument"></param>
        public void RaiseCallbackEvent(string eventArgument)
        {
            Int32 index = 0;
            if (Int32.TryParse(eventArgument, out index))
                returnValueAjax = this.GetListViewDetail(index);
            else
                returnValueAjax = this.GetListViewDetail(-1);
        }

        #endregion
    }
}
